package com.googlecode.connectlet.crypto.stream.provider;

import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.Key;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;

import javax.crypto.CipherSpi;

import com.googlecode.connectlet.crypto.stream.StreamCipher;

public abstract class StreamCipherSpi extends CipherSpi {
	@Deprecated
	@Override
	protected void engineSetMode(String mode) {
		throw new UnsupportedOperationException();
	}

	@Deprecated
	@Override
	protected void engineSetPadding(String padding) {
		throw new UnsupportedOperationException();
	}

	protected abstract StreamCipher getCipher(byte[] key);

	protected StreamCipher cipher = null;

	@Override
	protected int engineGetBlockSize() {
		return 0;
	}

	@Override
	protected void engineInit(int opmode, Key key, SecureRandom random) {
		cipher = getCipher(key.getEncoded());
	}

	@Override
	protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
			SecureRandom random) throws InvalidAlgorithmParameterException {
		engineInit(opmode, key, random);
	}

	@Override
	protected void engineInit(int opmode, Key key, AlgorithmParameters params,
			SecureRandom random) throws InvalidAlgorithmParameterException {
		engineInit(opmode, key, random);
	}

	@Override
	protected byte[] engineGetIV() {
		return null;
	}

	@Override
	protected AlgorithmParameters engineGetParameters() {
		return null;
	}

	@Override
	protected int engineGetOutputSize(int inputLen) {
		return inputLen;
	}

	@Override
	protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
		return cipher.update(input, inputOffset, inputLen);
	}

	@Override
	protected int engineUpdate(byte[] input, int inputOffset, int inputLen,
			byte[] output, int outputOffset) {
		cipher.update(input, inputOffset, output, outputOffset, inputLen);
		return inputLen;
	}

	@Override
	protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) {
		byte[] result = cipher.update(input, inputOffset, inputLen);
		cipher.reset();
		return result;
	}

	@Override
	protected int engineDoFinal(byte[] input, int inputOffset, int inputLen,
			byte[] output, int outputOffset) {
		cipher.update(input, inputOffset, output, outputOffset, inputLen);
		cipher.reset();
		return inputLen;
	}
}